package com.chenyuxin.ilp.security.config;


import com.chenyuxin.ilp.security.auth.handler.LoginFailHandler;
import com.chenyuxin.ilp.security.auth.handler.LoginSuccessHandler;
import com.chenyuxin.ilp.security.auth.password.PasswordAuthenticationFilter;
import com.chenyuxin.ilp.security.auth.password.PasswordAuthenticationProvider;
import com.chenyuxin.ilp.security.auth.sms.SmsAuthenticationFilter;
import com.chenyuxin.ilp.security.auth.sms.SmsAuthenticationProvider;
//import com.chenyuxin.ilp.security.perm.jwt.UserJWTAuthenticationFilter;
//import com.chenyuxin.ilp.security.perm.handler.PermExceptionHandler;
//import com.chenyuxin.ilp.security.perm.refresh.RefreshTokenAuthenticationFilter;
import com.chenyuxin.ilp.security.perm.handler.PermExceptionHandler;
import com.chenyuxin.ilp.security.perm.jwt.UserJWTAuthenticationFilter;
import com.chenyuxin.ilp.security.perm.refresh.RefreshTokenAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextHolderFilter;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;
import java.util.List;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    // 删除无用的过滤器
    private void commonHttpSetting(HttpSecurity http)throws Exception{
        // 表单登录/登出、session管理、csrf防护等默认配置，如果不disable。会默认创建默认filter
        http.cors().and()
                .formLogin(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable)
                .logout(AbstractHttpConfigurer::disable)
                .sessionManagement(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable)
                .cors(cors->{
                    cors.configurationSource(corsConfigurationSource());
                })
                // requestCache用于重定向，前后端分析项目无需重定向，requestCache也用不上
                .requestCache(cache -> cache
                        .requestCache(new NullRequestCache())
                )
                // 无需给用户一个匿名身份
                .anonymous(AbstractHttpConfigurer::disable);
    }
    // 注册过滤链
    @Order(1)
    @Bean
    public SecurityFilterChain loginFilterChain(HttpSecurity http)throws Exception {
        // 删除无效过滤链
        this.commonHttpSetting(http);
        // 只过滤登录请求
        http.securityMatcher("/user/login/**");
        // 获取handler对象
        LoginSuccessHandler loginSuccessHandler = applicationContext.getBean(LoginSuccessHandler.class);
        LoginFailHandler loginFailHandler = applicationContext.getBean(LoginFailHandler.class);
        // 注册密码登录过滤器
        PasswordAuthenticationFilter passwordAuthenticationFilter = new PasswordAuthenticationFilter(
                new AntPathRequestMatcher("/user/login/password", HttpMethod.POST.name()),
                new ProviderManager(List.of(applicationContext.getBean(PasswordAuthenticationProvider.class))),
                loginSuccessHandler,
                loginFailHandler);
        http.addFilterBefore(passwordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        // 注册手机号验证码登录拦截器
        SmsAuthenticationFilter smsAuthenticationFilter = new SmsAuthenticationFilter(
                new AntPathRequestMatcher("/user/login/phonecode", HttpMethod.POST.name()),
                new ProviderManager(List.of(applicationContext.getBean(SmsAuthenticationProvider.class))),
                loginSuccessHandler,
                loginFailHandler);
        http.addFilterBefore(smsAuthenticationFilter,UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Order(3)
    @Bean
    public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception {
        commonHttpSetting(http);
        http.addFilterBefore(new PermExceptionHandler(), SecurityContextHolderFilter.class);
        http.securityMatcher("/user/token",
                        "/user/head/**",
                        "user/statistic",
                        "user/storage",
                        "/file/**",
                        "/plans/**",
                        "/community/**")
                .authorizeHttpRequests(authorize->authorize.anyRequest().authenticated());
        http.addFilterBefore(new UserJWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
    @Order(2)
    @Bean
    public SecurityFilterChain refreshFilterChain(HttpSecurity http) throws Exception{
        commonHttpSetting(http);
        http.addFilterBefore(new PermExceptionHandler(), SecurityContextHolderFilter.class);
        http.securityMatcher("/user/refresh")
                .authorizeHttpRequests(authorize->authorize.anyRequest().authenticated());;
        http.addFilterBefore(new RefreshTokenAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .cors(Customizer.withDefaults())  // 启用 CORS
                .csrf(AbstractHttpConfigurer::disable); // 关闭 CSRF，避免影响跨域请求

        return http.build();
    }

//    @Bean
//    public CorsConfigurationSource corsConfigurationSource() {
//        CorsConfiguration configuration = new CorsConfiguration();
//        configuration.addAllowedOrigin("*"); // 允许的域名
//        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
//        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
//        configuration.setAllowCredentials(true); // 允许携带 Cookies
//
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        source.registerCorsConfiguration("/**", configuration);
//        return source;
//    }
@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.addAllowedOrigin("*");
    configuration.addAllowedMethod("*");
    configuration.addAllowedHeader("*");
    configuration.addExposedHeader("Authorization");
    configuration.addExposedHeader("Refresh-Token");
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }

}
